#ifndef B2D_IGRAPHICSDEVICE_H
#define B2D_IGRAPHICSDEVICE_H

#include "IUncopyable.h"
#include "IRenderable.h"
#include "ITexture.h"
#include "IShaderProgram.h"
#include "RenderTarget.h"

NS_B2D_BEGIN

class VertexBuffer;
class IndexBuffer;
class RenderOperation;
class RenderTexture;
class IGraphicContext;

////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief	Abstract graphics device.
/// 		Creates layer of abstraction between APIs
////////////////////////////////////////////////////////////////////////////////////////////////////
class B2D_API IGraphicsDevice
	: public IUncopyable
{
public:
	virtual ~IGraphicsDevice(void) { }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Sets a viewport.
	///
	/// \param	x	The x coordinate.
	/// \param	y	The y coordinate.
	/// \param	w	The width.
	/// \param	h	The height.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void setViewport(int x, int y, size_t w, size_t h) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets active render target.
	///
	/// \return	Active render target.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual RenderTarget* getActiveRenderTarget(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Creates texture render target.
	///
	/// \param	texCount	Number of texture attachments.
	///
	/// \return	The new texture render target.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual RenderTexture* createRenderTexture(size_t texCount) = 0;


	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Creates a vertex buffer.
	///
	/// \return	The new vertex buffer.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual VertexBuffer* createVertexBuffer(void) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Creates an index buffer.
	///
	/// \return	The new index buffer.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual IndexBuffer* createIndexBuffer(void) = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets active shader program.
	///
	/// \return	The active shader program.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual ShaderProgramPtr getActiveShaderProgram(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Sets active shader program.
	///
	/// \param 	sp	Active shader program.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void setActiveShaderProgram(const ShaderProgramPtr& sp) = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Sets texture slot.
	///
	/// \param	slot		The slot.
	/// \param 	texture		Texture for that slot. If null, the slot will be deactivated.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void setTextureSlot(TextureUnit::Unit unit, TexturePtr texture) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets active texture count.
	///
	/// \return	The active texture count.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual size_t getActiveTextureCount(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets texture in given slot.
	///
	/// \param	slot	The slot.
	///
	/// \return	Texture if slot in use, null otherwise.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual TexturePtr getTextureAt(TextureUnit::Unit slot) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Clears the textures.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void clearTextures(void) = 0;


	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Sets blending options.
	/// 		To disable blending src=ONE dst=ZERO.
	///
	/// \param	src			Source alpha.
	/// \param	dst			Destination alpha.
	/// \param	function	The function.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void setBlending(BlendCoefficient src, BlendCoefficient dst, BlendFunction function) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets blending options.
	///
	/// \param [out]	src			Source alpha.
	/// \param [out]	dst			Destination alpha.
	/// \param [out]	function	The function.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void getBlending(BlendCoefficient& src, BlendCoefficient& dst, BlendFunction& function) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets blending source coefficient.
	///
	/// \return	The blending source coefficient.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual BlendCoefficient getBlendingSrcCoefficient(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets blending destination coefficient.
	///
	/// \return	The blending destination coefficient.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual BlendCoefficient getBlendingDstCoefficient(void) const = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Gets blending function.
	///
	/// \return	The blending function.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual BlendFunction getBlendingFunction(void) const = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Clears the frame buffers requested with the values provided.
	///
	/// \param	buffers	Bitmask flags of buffers to clear.
	/// \param	color  	The clearing color.
	/// \param	depth  	The depth to clear.
	/// \param	stencil	The number of stencil bits.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void clearFrameBuffers(uint buffers, const Color& color, float depth, ushort stencil) = 0;

_internal:
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Creates the API-specific context.
	///
	/// \return	The new context.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual IGraphicContext* _createGraphicsContext(void) = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Sets active render target.
	///
	/// \param rt	Render target.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void _setActiveRenderTarget(const RenderTarget& rt) = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Renders the given operation.
	///
	/// \param	op	The operation.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void _render(const RenderOperation& op) = 0;
};

NS_B2D_END

#endif